﻿// Inner Fire 游戏引擎库
// InstancedSprites - 实例精灵绘制器
//
// Copyright (c) 2025 by 尔西大帝. All rights reserved.
//
// 所属层级：元素层（3）
// 对精灵实例进行绘制。只需要记录位置信息。其它的都是GPU计算。只有单一颜色。
// 粒子系统虽然使用相同的东西，但是使用另外一个类进行管理。这里只用于调试（意味着可以使用极高速的Shader）。
//
// Author: 尔西大帝
// Email: 2670613871@qq.com
// Created: 2025-05-21

#pragma once

#include <dx/core/dx_core.h>
#include <dx/core/dx_element.h>
#include <dx/core/upload_buffer.h>
#include <dx/mesh/basic_render_item.h>
#include <dx/texture/dx_material.h>
#include <graphics/frame_resources_def.h>
#include <graphics/instanced_def.h>
#include <graphics/vertex_list.h>

namespace ifire::dx {
// InstancedSprite类型，决定不同的绘制
enum class InstancedSpriteType {
  // 通过一个Mesh绘制，但不会有贴图采样，只有纯色，而且没有旋转的分量，减少计算。
  // Position1为位置，Position2无效，Color为颜色。
  Point,
  // 通过一个线段绘制。Position1为开始点，Position2为结束点。Color为颜色。
  Line,
  // 通过一个Mesh绘制，拥有纹理采样。Position1为位置，Position2为旋转。Color为缩放。
  Mesh,
};

class InstancedSprites : public BasicRenderItem {
public:
  InstancedSprites(
      InstancedSpriteType sprite_type, DxMesh* mesh, size_t count);
  InstancedSprites(const InstancedSprites& rhs) = delete;
  InstancedSprites& operator=(const InstancedSprites& rhs) = delete;
  ~InstancedSprites() = default;

  // 根据精灵更新项目
  void Update(UploadBuffer<InstancedSpriteConstants>* main_buffer,
      UploadBuffer<InstancedSpriteData>* sprite_buffer);
  // 设置一个精灵项目的坐标
  void SetPosition(int index, IVec3 position);
  // 设置一个精灵项目的变换
  void SetTransform(
      int index, IVec3 position, IVec4 rotation, IVec3 scale);
  // 设置一个精灵项目的颜色
  void SetColor(int index, IVec4 color);
  // 设置一个精灵项目的线段
  void SetLine(int index, IVec3 start, IVec3 end);
  // 一并设置所有项目的颜色，指定开始(索引)与结束(索引)。结果end=0，表示设置直到最后。
  void SetAllColor(IVec4 color, int start = 0, int end = 0);

  // ------
  // 属性访问
  // ------
  eastl::vector<InstancedSprite>& Sprites() { return sprites_; }
  const DxMesh* GetMesh() const { return mesh_; }
  UINT GetDrawCount() const { return draw_count_; }
  void SetDrawCount(size_t count) { draw_count_ = static_cast<UINT>(count); }
  InstancedSpriteType GetSpriteType() const { return sprite_type_; }
  void SetMaterial(Material* value) { material_ = value; }
  const Material* GetMaterial() const { return material_; }

public:
  // 此项目的矩阵
  DirectX::XMFLOAT4X4 world;
  // 此项目的颜色
  IVec4 color;
  // 此项目中每一个子项目的缩放
  IVec3 scale;

private:
  // 此项目的类型
  InstancedSpriteType sprite_type_;
  // 此项目的精灵数量
  UINT draw_count_;
  // 此项目的精灵
  eastl::vector<InstancedSprite> sprites_;
  // 此项目的顶点（由一个模型直接赋予）
  DxMesh* mesh_;
  // 材质
  Material* material_;
};

using InstancedSpritesPtr = std::unique_ptr<InstancedSprites>;

InstancedSpriteType ParseInstancedSpriteType(ikit::sstr name);

} // namespace ifire::dx